package sg.edu.nus.iss.vmcs.customer;

/*
 * Copyright 2003 ISS.
 * The contents contained in this document may not be reproduced in any
 * form or by any means, without the written permission of ISS, other
 * than for the purpose for which it has been supplied.
 *
 */

import java.awt.Button;
import java.awt.Dialog;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import sg.edu.nus.iss.vmcs.system.ProductFactory;
import sg.edu.nus.iss.vmcs.system.SimulatorControlPanel;
import sg.edu.nus.iss.vmcs.util.LabelledDisplay;
import sg.edu.nus.iss.vmcs.util.WarningDisplay;

/**
 * This panel simulates the vending machine's customer interface panel. It will 
 * enable the user (the Customer) to:
 * 
 * 1. insert coins;
 * 2. select brands;
 * 3. terminate transaction.
 * It will also provide the following display functions:
 * 1. display total money inserted;
 * 2. indicate coin not valid;
 * 3. indicate no change available;
 * 4. display the value of the change to be collected;
 * 5. display an icon representing the dispensed product.
 * 
 * @version 1.0 11 Oct 2008
 * @author Toh Kim Huat
 */
public class CustomerPanel extends Dialog {

	private static final String TITLE = "VMCS - Customer Panel";
	private static final String TITLE_LABEL = "VIMTO Soft Drink Dispenser";
	private static final String LABEL_INVALID_COIN = "Invalid Coin";
	private static final String LABEL_TOTAL_MONEY_INSERTED = "Total Money Inserted:";
	private static final String LABEL_NO_CHANGE_AVAILABLE = "No Change Available";
	private static final String LABEL_TERMINATE_AND_RETURN_CASH = "Terminate and Return Cash";
	private static final String LABEL_COLLECT_COINS = "Collect Coins:";
	private static final String LABEL_COLLECT_CANS_HERE = "Collect Can Here:";
	private static final String LABEL_NO_CAN = "NO CAN";
	private static final String LABEL_NO_CHANGE = "0 C";
	
	public static final int COMPONENT_COIN_INPUT_BOX = 1;
	public static final int COMPONENT_PRODUCT_SELECTION_BOX = 2;
	public static final int COMPONENT_TERMINATE_BUTTON = 3;

	/**
	 * Generated serial version uid
	 */
	private static final long serialVersionUID = 251836640115983121L;
	
	/**
	 * Reference to the transaction controller which created this panel
	 */
	private TransactionController transactionController;
	
	/**
	 * Coin input box 
	 */
	private CoinInputBox coinInputBox;
	
	/**
	 * Product selection box
	 */
	private ProductSelectionBox productSelectionBox;
	
	/**
	 * Terminate button
	 */
	private Button terminateButton;
	
	/**
	 * No Change Available Display
	 */
	private WarningDisplay noChangeAvailableDisplay;
	
	/**
	 * Invalid Coin Display
	 */
	private WarningDisplay invalidCoinDisplay;
	
	/**
	 * Total money inserted display
	 */
	private LabelledDisplay totalMoneyInsertedDisplay;
	
	/**
	 * Refund/Change Tray display
	 */
	private LabelledDisplay refundChangeTrayDisplay;
	
	/**
	 * Can Collection Box
	 */
	private LabelledDisplay canCollectionBox;
	
	/**
	 * This constructor creates an instance of the CustomerPanel. It further
	 * creates Invalid Coin display, No Change Available Display, Refund/Change
	 * Tray Display, Total Money Inserted Display, Coin Input Box, Product
	 * Selection Box, Can Collection Box and Terminate Button
	 * 
	 * @param transactionController
	 *            Reference to the transaction controller which created this
	 *            panel
	 */
	public CustomerPanel(Frame parentFrame,
			TransactionController transactionController) {
		
		super(parentFrame, TITLE, false);

		this.transactionController = transactionController;

		// set up the title panel
		Panel titlePanel = new Panel(new GridLayout(1, 0));
		Label titleLabel = new Label(TITLE_LABEL);
		titleLabel.setAlignment(Label.CENTER);
		titleLabel.setFont(new Font("Helvetica", Font.PLAIN, 18));
		titlePanel.add(titleLabel);
		
		// set up the coin input box
		this.coinInputBox = new CoinInputBox(this, transactionController.getCoinInputAdapter());
		
		// set up the invalid coin display
		this.invalidCoinDisplay = new WarningDisplay(LABEL_INVALID_COIN);
		
		// set up the total money inserted display
		this.totalMoneyInsertedDisplay = new LabelledDisplay(
				LABEL_TOTAL_MONEY_INSERTED, 5, LabelledDisplay.FLOW);
		this.totalMoneyInsertedDisplay.setValue("0 C");
		this.totalMoneyInsertedDisplay.setEditable(false);
		
		// set up the Product selection box
		this.productSelectionBox = ProductFactory.getFactory()
				.createSelectionBox(this, transactionController);

		// set up the no change available display
		this.noChangeAvailableDisplay = new WarningDisplay(
				LABEL_NO_CHANGE_AVAILABLE);

		// set up the terminate and return cash button
		this.terminateButton = new Button(LABEL_TERMINATE_AND_RETURN_CASH);
		this.terminateButton.addActionListener(new TerminateButtonListener(
				transactionController));

		// set up the collect coins labelled display
		this.refundChangeTrayDisplay = new LabelledDisplay(LABEL_COLLECT_COINS,
				5, LabelledDisplay.FLOW);
		this.refundChangeTrayDisplay.setValue(LABEL_NO_CHANGE);
		this.refundChangeTrayDisplay.setEditable(false);

		// set up the collect can here labelled display
		this.canCollectionBox = new LabelledDisplay(LABEL_COLLECT_CANS_HERE,
				10, LabelledDisplay.FLOW);
		this.canCollectionBox.setValue(LABEL_NO_CAN);
		this.canCollectionBox.setEditable(false);
		
		GridBagLayout gb= new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		this.setLayout(gb);
		
		c.fill = GridBagConstraints.BOTH;
        c.weightx = 1.0;
        c.gridwidth = GridBagConstraints.REMAINDER;

        this.setLayout(gb);
		gb.setConstraints(titlePanel, c);
		this.add(titlePanel);
        c.gridheight = 2;
		c.weighty = 1.0;

		gb.setConstraints(coinInputBox, c);
		this.add(coinInputBox);
		c.gridheight = 1;
		c.weighty = 0;
		gb.setConstraints(invalidCoinDisplay, c);
		this.add(invalidCoinDisplay);
		gb.setConstraints(totalMoneyInsertedDisplay, c);
		this.add(totalMoneyInsertedDisplay);
		c.gridheight = 2;
		c.weighty = 1.0;
		gb.setConstraints(productSelectionBox, c);
		this.add(productSelectionBox);
		c.gridheight = 1;
		c.weighty = 0;
		gb.setConstraints(noChangeAvailableDisplay, c);
		this.add(noChangeAvailableDisplay);
		c.fill = GridBagConstraints.CENTER;
		gb.setConstraints(terminateButton, c);
		this.add(terminateButton);
		gb.setConstraints(refundChangeTrayDisplay, c);
		this.add(refundChangeTrayDisplay);
		gb.setConstraints(canCollectionBox, c);
		this.add(canCollectionBox);
				
		this.setResizable(false);
		
		pack();

        addWindowListener(new WindowAdapter() {
		     public void windowClosing(WindowEvent e) {
		          closeDown();
		     }
	     });
		
	}
	
	/**
	 * Remove the Customer Panel from the display.
	 */
	public void closeDown() {
		SimulatorControlPanel simulatorControlPanel = this.transactionController
				.getMainController().getSimulatorControlPanel();
		simulatorControlPanel.setActive(SimulatorControlPanel.ACT_CUSTOMER,
				true);
		this.dispose();
	}
	
	/**
	 * Display the Customer Panel. This will be achieved by displaying the frame
	 * of the panel and then sending messages to its constituent objects
	 * instructing them to display themselves.
	 */
	public void display() {
		this.setVisible(true);
	}
	
	/**
	 * This operation activates or deactivates the Customer Panel and its
	 * component objects
	 * 
	 * @param active
	 *            Boolean indicating whether it is active
	 * @param component
	 *            Component identifier
	 */
	public void setActive(boolean active, int component) {
		switch (component) {
		case COMPONENT_COIN_INPUT_BOX:
			this.coinInputBox.setActive(active);
			break;
		case COMPONENT_PRODUCT_SELECTION_BOX:
			this.productSelectionBox.setActive(active);
			break;
		case COMPONENT_TERMINATE_BUTTON:
			this.terminateButton.setEnabled(active);
			break;
		}
	}

	public CoinInputBox getCoinInputBox() {
		return coinInputBox;
	}

	public ProductSelectionBox getProductSelectionBox() {
		return productSelectionBox;
	}

	public WarningDisplay getNoChangeAvailableDisplay() {
		return noChangeAvailableDisplay;
	}

	public WarningDisplay getInvalidCoinDisplay() {
		return invalidCoinDisplay;
	}

	public LabelledDisplay getTotalMoneyInsertedDisplay() {
		return totalMoneyInsertedDisplay;
	}

	public LabelledDisplay getRefundChangeTrayDisplay() {
		return refundChangeTrayDisplay;
	}

	public LabelledDisplay getCanCollectionBox() {
		return canCollectionBox;
	}

}
